<template>
  <!-- 
    自定义数字展示组件 AxiomNumber。
    支持数字动画、格式化、前缀后缀、趋势指示等功能。
  -->
  <div class="axiom-number" :class="[`axiom-number--${size}`, `axiom-number--${variant}`]">
    <!-- 标签 -->
    <div v-if="label" class="axiom-number__label">
      {{ label }}
    </div>
    
    <!-- 数字主体 -->
    <div class="axiom-number__main">
      <!-- 前缀 -->
      <span v-if="prefix" class="axiom-number__prefix">
        {{ prefix }}
      </span>
      
      <!-- 数字值 -->
      <span 
        class="axiom-number__value"
        :class="{
          'axiom-number__value--positive': trend === 'up',
          'axiom-number__value--negative': trend === 'down',
          'axiom-number__value--neutral': trend === 'neutral'
        }"
      >
        {{ displayValue }}
      </span>
      
      <!-- 后缀 -->
      <span v-if="suffix" class="axiom-number__suffix">
        {{ suffix }}
      </span>
      
      <!-- 趋势指示器 -->
      <div v-if="showTrend && trend !== 'neutral'" class="axiom-number__trend">
        <component :is="getTrendIcon()" class="axiom-number__trend-icon" />
        <span v-if="trendValue" class="axiom-number__trend-value">
          {{ formatTrendValue(trendValue) }}
        </span>
      </div>
    </div>
    
    <!-- 描述文本 -->
    <div v-if="description" class="axiom-number__description">
      {{ description }}
    </div>
    
    <!-- 额外信息 -->
    <div v-if="$slots.extra" class="axiom-number__extra">
      <slot name="extra"></slot>
    </div>
  </div>
</template>

<script>
import { computed, watch, onMounted } from 'vue'
import { ArrowUp, ArrowDown } from '@element-plus/icons-vue'
// import { GlobalUtilsMixin } from '@/utils/globalUtils';

export default {
  name: 'AxiomNumber',
  components: {
    ArrowUp,
    ArrowDown
  },
  // mixins: [GlobalUtilsMixin],
  props: {
    value: { type: [Number, String], default: 0 },
    label: { type: String, default: '' },
    prefix: { type: String, default: '' },
    suffix: { type: String, default: '' },
    description: { type: String, default: '' },
    size: { type: String, default: 'default', validator: (v) => ['small', 'default', 'large'].includes(v) },
    variant: { type: String, default: 'default', validator: (v) => ['default', 'card', 'minimal'].includes(v) },
    animated: { type: Boolean, default: true },
    duration: { type: Number, default: 1000 },
    precision: { type: Number, default: 0 },
    separator: { type: String, default: ',' },
    formatter: { type: Function, default: undefined },
    trend: { type: String, default: 'neutral', validator: (v) => ['up', 'down', 'neutral'].includes(v) },
    showTrend: { type: Boolean, default: false },
    trendValue: { type: [Number, String], default: '' },
    trendFormat: { type: String, default: 'percent', validator: (v) => ['percent', 'absolute'].includes(v) }
  },
  data() {
    return {
      currentValue: 0
    }
  },
  computed: {
    displayValue() {
      if (this.formatter) {
        return this.formatter(this.currentValue)
      }
      return this.formatNumber(this.currentValue)
    }
  },
  watch: {
    value(newValue, oldValue) {
      const from = Number(oldValue) || 0
      const to = Number(newValue) || 0
      this.animateNumber(from, to, this.duration)
    }
  },
  methods: {
    formatNumber(num) {
      const number = Number(num)
      if (isNaN(number)) return '0'
      const fixed = number.toFixed(this.precision)
      if (this.separator) {
        const parts = fixed.split('.')
        parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.separator)
        return parts.join('.')
      }
      return fixed
    },
    formatTrendValue(value) {
      const num = Number(value)
      if (isNaN(num)) return value
      if (this.trendFormat === 'percent') {
        return `${num > 0 ? '+' : ''}${num.toFixed(1)}%`
      } else {
        return `${num > 0 ? '+' : ''}${this.formatNumber(num)}`
      }
    },
    getTrendIcon() {
      return this.trend === 'up' ? ArrowUp : ArrowDown
    },
    animateNumber(from, to, duration) {
      if (!this.animated) {
        this.currentValue = to
        return
      }
      const startTime = Date.now()
      const difference = to - from
      const step = () => {
        const elapsed = Date.now() - startTime
        const progress = Math.min(elapsed / duration, 1)
        const easeOutQuart = 1 - Math.pow(1 - progress, 4)
        this.currentValue = from + difference * easeOutQuart
        if (progress < 1) {
          requestAnimationFrame(step)
        } else {
          this.currentValue = to
        }
      }
      requestAnimationFrame(step)
    }
  },
  created() {
    // this.$logger.debug('AxiomNumber 组件初始化', { value: this.value, animated: this.animated, trend: this.trend });
  },
  mounted() {
    const targetValue = Number(this.value) || 0
    if (this.animated) {
      this.animateNumber(0, targetValue, this.duration)
    } else {
      this.currentValue = targetValue
    }
  }
}
</script>

<style lang="scss">
@use '../../styles/components/common/axiom-number';
</style>